(* file: interface_gtk.ml *)

(* Globals, say *)

let heading = ref 80;; 
let speed = ref 10.0;; 
let gheading = ref 90;;
let maxspeed = 30.;;
let graphics_showed = ref true;;
 

(* Little hack-interface with the command line *)
 
try
  heading := int_of_string Sys.argv.(1);
  speed := float_of_string  Sys.argv.(2);
  gheading := int_of_string Sys.argv.(3)
with 
    _ ->  ()
;;

(* Just to be sure that GTK well behaves *) 
let locale = GtkMain.Main.init ();;


(* Standard callbacks *)
let delete_event ev =
 GMain.Main.quit ();
 false
;;

let my_exit () =
 GMain.Main.quit ()
;;

(* Start defining GTK widgets *)

let window = GWindow.window 
	       ~title:"VMG Calculator" 
	       ~border_width:10 
	       ~allow_grow:false
	       () 
;;


let mainbox = GPack.vbox ~packing:window#add ()
;;

(* The About window *)

let  about_dialog  =  ref (fun () -> raise Not_found) 
;;


let do_about () = try !about_dialog () with
    Not_found  ->
      let
	message = "An application written in the OCAML language and\n"^
		  "ported to WIN32 using the "^
		  "Fedora 10 MinGW crosscompilers and tools.\n"  
      in
      let 
	dialog = GWindow.about_dialog
		   ~authors:["Luigi Santocanale"]
		   ~version:"0.0.1"
		   ~copyright:"@Luigi Santocanale"
		   ~license:Licence.licence
		   (*~wrap_license:true*)
		   ~title:"About"
		   ~comments:message	      
		   ()
      in
      let
	_ =
	dialog#connect#response ~callback:(fun _ -> dialog#destroy ())
      in
	(*about_dialog := dialog#present ; *)
	dialog#show ()
 ;;


(* The Menu *)

let file_entries = [
  `I ("Quit", GMain.Main.quit )
]
;;

let help_entries = [
  `I ("About", do_about);
]
;;

let entries = [
  `M ("File", file_entries);
  `M ("Help", help_entries)
]
;;

let create_menu label menubar =
  let 
    item = GMenu.menu_item ~label ~packing:menubar#append () 
  in
    GMenu.menu ~packing:item#set_submenu ()
;;

let do_menu () =
  let 
    menubar = GMenu.menu_bar ~packing:mainbox#add () 
  in
  let 
    menu = create_menu "File" menubar 
  in
    GToolbox.build_menu menu ~entries:file_entries;
    let 
      menu = create_menu "Help" menubar 
    in
      GToolbox.build_menu menu ~entries:help_entries;
;;

let _ = do_menu ()
;;

(* Spinners : Cap, vitesse, cap souhaite' *)

let spinner_box = GPack.hbox ~packing:mainbox#add ()
;;
  
let heading_spinner =
  let 
    vbox2 = GPack.vbox ~packing:spinner_box#add () 
  in 
  let _ = 
    GMisc.label ~text:"Cap" 
      ~xalign:0.5 ~yalign:0.5 ~packing:vbox2#add () 
  and
    adj = GData.adjustment 
	    ~value:(float_of_int (!heading)) 
            ~lower:0.0 ~upper:359.0 
            ~step_incr:1.0 ~page_incr:5.0 ~page_size:0.0 () 
  in
    GEdit.spin_button 
      ~numeric:true 
      ~adjustment:adj 
      ~rate:0.0 ~digits:0 
      ~wrap:true 
      ~packing:vbox2#add  ()
;;

  
let speed_spinner =
  let 
    vbox2 = GPack.vbox ~packing:spinner_box#add () 
  in
  let _ =
    GMisc.label 
      ~text:"Vitesse" ~xalign:0.5 ~yalign:0.5 ~packing:vbox2#add () 
  and
    adj = GData.adjustment 
	    ~value:(!speed)
	    ~lower:0.0 ~upper:maxspeed ~step_incr:0.1 ~page_incr:1.0 ~page_size:0.0 () 
  in
    GEdit.spin_button ~adjustment:adj ~rate:0.0 ~digits:1 ~wrap:false ~packing:vbox2#add () 
;;

let wheading_spinner =
  let 
    vbox2 = GPack.vbox ~packing:spinner_box#add () 
  in
  let  _ =
    GMisc.label 
      ~text:"Cap souhaite'" ~xalign:0.5 ~yalign:0.5 ~packing:vbox2#add ()
  and  
    adj = GData.adjustment 
	    ~value:(float_of_int (!gheading))
	    ~lower:0.0 ~upper:359.0 ~step_incr:1.0 ~page_incr:5.0 ~page_size:0.0 () 
  in
    GEdit.spin_button ~adjustment:adj ~rate:0.0 ~digits:0 ~wrap:true ~packing:vbox2#add ()
;;  


let vmg_label =
  let hbox = GPack.hbox ~packing:mainbox#add () in
  let _ =
    GMisc.label ~text:"VMG : " ~xalign:0.0 ~yalign:0.5 ~packing:hbox#add ()
  in
    GMisc.label ~text:"10.0"
	  ~xalign:0.0 ~yalign:0.5 ~packing:hbox#add 
	  ~width:40
	  () 
;;


(* Drawing area *)

let drawing_area = 
  let hbox = GPack.hbox ~packing:mainbox#add () in
    GMisc.drawing_area 
      ~packing:hbox#add
      ~height:480
      ~width:480 
      ()
;; 

(* ... with a drawing inside *)
 
let drawing = 
    drawing_area#misc#realize ();
    new GDraw.drawable (drawing_area#misc#window) 
;;




let show_graphics_button = GButton.button 
		    ~label:"Hide Graphics" 
		    ~packing:mainbox#pack ()
;;

(* End of GTK Widgets *)



let vmg_compute cap vit capsouait vmg_entry () = 
  let vmg = (Vmg.vmg (cap#value_as_int,vit#value,capsouait#value_as_int)) in
  let rounded_vmg = float_of_int (truncate (vmg*.100.))/. 100. in
  let str_vmg = string_of_float rounded_vmg in
    vmg_entry#set_text str_vmg  
;;

let rec list_of first last step plus =
  if last < first then [] else 
    first::(list_of (plus first step) last step plus)
;;


let draw (h,s,wh) =
  let 
    projection = Vector.Vec (wh,Vmg.vmg (h,s,wh))
  in
    GraphicsGTK.set_color GraphicsGTK.White;
    GraphicsGTK.draw_area Vector.center maxspeed;
    GraphicsGTK.set_color GraphicsGTK.Black;
    GraphicsGTK.set_line_width 1;
    List.iter 
      (fun x -> GraphicsHIGH.draw_pointed_line (Vector.Vec (x,27.))) 
      (list_of 0 359 30 (+));
    List.iter 
      (fun x -> GraphicsHIGH.draw_pointed_circle x)
      (list_of 5. 25. 5. (+.));
    GraphicsGTK.set_line_width 2;
    GraphicsHIGH.draw_arrow (Vector.Vec (h, s)) GraphicsGTK.Red;
    GraphicsHIGH.draw_arrow projection GraphicsGTK.Blue;
;;


let main_callback () = 
  let 
    heading = heading_spinner#value_as_int
  and
    speed = speed_spinner#value
  and
    gheading = wheading_spinner#value_as_int
  in
  let
    vmg = (Vmg.vmg (heading,speed,gheading))
  in
  let 
    rounded_vmg = float_of_int (truncate (vmg*.100.))/. 100. 
  in
  let 
    str_vmg = string_of_float rounded_vmg 
  in
    vmg_label#set_text str_vmg;
    draw (heading,speed,gheading) 
;;

(* What the show graphics should do ? *)
let show_close_graphics () =
  if !graphics_showed = true then
    ( graphics_showed := false;
      show_graphics_button#set_label "Show graphics"; 
      drawing_area#misc#hide ()
    )
  else
    ( graphics_showed := true;
      show_graphics_button#set_label "Hide graphics"; 
      drawing_area#misc#show ()
    )
;;
 
let main () =	  
  (* Connect GTK signals with callbacks *)
  (* We do not care about the events returned *) 
  let 
    _ = window#event#connect#delete ~callback:delete_event 
  and
    _ = heading_spinner#connect#value_changed ~callback:main_callback
  and
    _ = speed_spinner#connect#value_changed ~callback:main_callback
  and
    _ = wheading_spinner#connect#value_changed ~callback:main_callback
  and
    _ = drawing_area#event#connect#expose 
	  ~callback:(fun _ ->  main_callback ();false) 
  and
    _ = show_graphics_button#connect#clicked 
	  ~callback:show_close_graphics
  in
    (* Init llo and high level graphics *)
    GraphicsGTK.init_graphics maxspeed drawing ;
    GraphicsHIGH.set_maxspeed maxspeed ;
    (* Show the window *)
    window#show ();
    (* Do what you are supoposed to do *)
    GMain.Main.main ()
;;

let _ = main ()
;;
